package com.example.demo.config;

import com.example.demo.common.Func;
import com.example.demo.common.Valid;
import com.example.demo.common.Result;
import com.example.demo.common.constant.ResultCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
@Slf4j
@RequiredArgsConstructor
public class InterceptorConfig implements HandlerInterceptor {

    /*private final RedisTemplate<String, String> redis;
    private final CustomeParam param;*/

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        //Func.print("执行到 preHandle");
        Result res = new Result();

        try {
            // 设置日志跟踪标识
            String traceId = request.getHeader("user_trace");
            if (Valid.isEmpty(traceId)) {
                //traceId = Func.getUUID().toUpperCase();
                traceId = Func.getULID();
            }
            MDC.put("traceId", traceId);

            // 如果是测试模式，不必检测
            /*if (param.isUseTestMode()) {
                return true;
            }*/

            // 如果是特定接口请求，不必检测
            /*if (filterKeywords(request)) {
                return true;
            }*/

            // 限制接口访问次数
            /*if (!limitAccess(request, response, handler)) {
                return false;
            }*/

            // 防止接口重复提交
            /*if (!prohibitRepeat(request, response, handler)) {
                return false;
            }*/

            // token验证
            /*if (!checkToken(request, response)) {
                return false;
            }*/

            // JWT签名验证
            /*if (!checkJwt(request, response)) {
                return false;
            }*/

            return true;
        } catch (Exception ex) {
            log.error("/Intercept/ValidException:" + ex);
            res.setSystemError(ResultCode.SYSTEM_INTERCEPT_ERROR);
            backException(response, res);
            return false;
        }
    }

    /*private boolean filterKeywords(HttpServletRequest request) {
        if (RequestMethod.OPTIONS.name().equals(request.getMethod())) {
            return true;
        }

        String serverPath = request.getServletPath();
        if (serverPath.equals("/")) {
            return true;
        }

        List<String> keywordsList = new ArrayList<>();
        keywordsList.add("/api/login");
        for (String temp : keywordsList) {
            if (!serverPath.contains("/api/") || serverPath.contains(temp)) {
                return true;
            }
        }

        return false;
    }*/

    /*private boolean limitAccess(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;

            //redis的实体类没有被注入初始化，出错
            if (redis == null) {
                log.info(ResultCode.USER_REDIS_INIT_ERROR.getMessage());
                res.setVisitError(ResultCode.USER_REDIS_INIT_ERROR);
                backException(response, res);
                return false;
            }

            //获取方法中的注解，看是否有该注解
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if (accessLimit != null) {
                //从redis中判断是否在被禁的IP列表内
                String ip = Func.getIP(request);
                List<String> ipList = redis.opsForList().range("forbid_ip", 0, -1);
                if (ipList.contains(ip)) {
                    log.info(ip + ResultCode.USER_IP_PROHIBIT.getMessage());
                    res.setVisitError(ResultCode.USER_IP_PROHIBIT);
                    backException(response, res);
                    return false;
                }

                //从redis中判断用户访问的次数
                int maxCount = accessLimit.maxCount();
                String key = ip + "_" + request.getServletPath();
                String count = redis.opsForValue().get(key);
                if (Valid.isEmpty(count)) {
                    redis.opsForValue().set(key, "1", 1, TimeUnit.SECONDS);
                }
                else {
                    if (Integer.parseInt(count) < maxCount) {
                        redis.opsForValue().set(key, String.valueOf(Integer.parseInt(count) + 1), 1, TimeUnit.SECONDS);
                    }
                    else {
                        redis.opsForList().rightPush("forbid_ip", ip);
                        redis.expire("forbid_ip", 60, TimeUnit.SECONDS);

                        log.info(ip + ResultCode.USER_IP_LIMITOUT.getMessage());
                        res.setVisitError(ResultCode.USER_IP_LIMITOUT);
                        backException(response, res);
                        return false;
                    }
                }
            }
        }

        return true;
    }*/

    /*private boolean prohibitRepeat(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;

            //redis的实体类没有被注入初始化，出错
            if (redis == null) {
                log.info(ResultCode.USER_REDIS_INIT_ERROR.getMessage());
                res.setVisitError(ResultCode.USER_REDIS_INIT_ERROR);
                backException(response, res);
                return false;
            }

            //获取方法中的注解，看是否有该注解
            ProhibitRepeat prohibitRepeat = hm.getMethodAnnotation(ProhibitRepeat.class);
            if (prohibitRepeat != null) {
                // 防重复提交的逻辑（将检查重复与否的标识放在Header）
                String prohibitId = request.getHeader("user_prohibit");
                if (Valid.isEmpty(prohibitId)) {
                    log.info(ResultCode.PROHIBIT_ID_IS_NULL.getMessage());
                    res.setVisitError(ResultCode.PROHIBIT_ID_IS_NULL);
                    backException(response, res);
                    return false;
                }

                String key = "prohibit:id:" + prohibitId;
                String value = redis.opsForValue().get(key);
                if (!Valid.isEmpty(value)) {
                    redis.delete(key);
                }
                else {
                    log.info(ResultCode.PROHIBIT_REPEAT.getMessage());
                    res.setVisitError(ResultCode.PROHIBIT_REPEAT);
                    backException(response, res);
                    return false;
                }
            }
        }

        return true;
    }*/

    /*private boolean checkToken(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader("user_token");
        String serverName = Func.getIP(request);
        String serverPath = request.getServletPath();

        //redis的实体类没有被注入初始化，出错
        if (redis == null) {
            log.info(ResultCode.USER_REDIS_INIT_ERROR.getMessage());
            res.setVisitError(ResultCode.USER_REDIS_INIT_ERROR);
            backException(response, res);
            return false;
        }

        //token为空，说明没有经过正常的登录操作
        if (Valid.isEmpty(token)) {
            log.info(serverName + "," + serverPath + ":" + ResultCode.USER_TOKEN_WEB_DELETION.getMessage());
            res.setVisitError(ResultCode.USER_TOKEN_WEB_DELETION);
            backException(response, res);
            return false;
        }

        //token里的内容项数少于6，出错（6项：用户ID、用户名、密码、姓名、上次操作的时间戳、标识本次登录行为的随机6位数）
        String separate1 = "@#&%", separate2 = "%@#&", separate3 = "&%@#", separate4 = "#&%@";
        String regex = "\\" + separate1 + "|" + separate2 + "|" + separate3 + "|" + separate4;
        String[] temp = token.split(regex);
        if (temp.length != 6) {
            log.info(serverName + "," + serverPath + ":" + ResultCode.USER_TOKEN_LENGTH_ERROR.getMessage());
            res.setVisitError(ResultCode.USER_TOKEN_LENGTH_ERROR);
            backException(response, res);
            return false;
        }

        //token里的6项内容任意一项为空，都不正常
        String userid = temp[0], username = temp[1], password = temp[2], name = temp[3], time = temp[4], random = temp[5];
        if (Valid.isEmpty(userid) || Valid.isEmpty(username) || Valid.isEmpty(password) ||
                Valid.isEmpty(name) || Valid.isEmpty(time) || Valid.isEmpty(random)) {
            log.info(userid + "," + serverName + "," + serverPath + ":" + ResultCode.USER_TOKEN_CONTENT_EMPTY.getMessage());
            res.setVisitError(ResultCode.USER_TOKEN_CONTENT_EMPTY);
            backException(response, res);
            return false;
        }

        //redis里没有查询到相应的key-value，出错
        String value = Func.decode(redis.opsForValue().get("shop_" + userid));
        if (Valid.isEmpty(value)) {
            log.info(userid + "," + serverName + "," + serverPath + ":" + ResultCode.USER_TOKEN_REDIS_DELETION.getMessage());
            res.setVisitError(ResultCode.USER_TOKEN_REDIS_DELETION);
            backException(response, res);
            return false;
        }

        //判断redis里的userid、username、password是否存在，若不存在，说明该账号的状态已被置为不可用
        String[] list = value.split(regex);
        if (!userid.equals(list[0]) || !username.equals(list[1]) || !password.equals(list[2])) {
            log.info(userid + "," + serverName + "," + serverPath + ":" + ResultCode.USER_TOKEN_CONTENT_ERROR.getMessage());
            res.setVisitError(ResultCode.USER_TOKEN_CONTENT_ERROR);
            backException(response, res);
            return false;
        }

        //姓名的格式不正确
        if (name.length() > 10 || Valid.isWicked(name)) {
            log.info(userid + "," + serverName + "," + serverPath + ":姓名的格式不正确");
            res.setVisitError("非法访问7");
            backException(response, res);
            return false;
        }

        //若随机6位数不相等，说明已在别处登录
        if (!random.equals(list[4])) {
            log.info(userid + "," + serverName + "," + serverPath + ":" + ResultCode.USER_TOKEN_RANDOM_ERROR.getMessage());
            res.setVisitError(ResultCode.USER_TOKEN_RANDOM_ERROR);
            backException(response, res);
            return false;
        }

        //判断时间间隔是否超过30分钟，若是，说明长时间不操作，须重新登录
        Long oldTime = Long.valueOf(list[3]);
        Long minutes = (System.currentTimeMillis() - oldTime) / (1000 * 60);
        if (minutes > param.getOvertimeMin()) {
            log.info(userid + "," + serverName + "," + serverPath + ":" + ResultCode.USER_TOKEN_TIMEOUT.getMessage());
            res.setVisitError(ResultCode.USER_TOKEN_TIMEOUT);
            backException(response, res);
            return false;
        }

        //判断时间间隔是否超过15分钟
        if (minutes > param.getIntervalMin()) {
            //进行用户信息的redis验证

            //只更新token中的时间戳
            String newToken = Func.encode(userid + separate1 + username + separate2 + password + separate3 + name + separate4 + new Date().getTime() + separate1 + random);
            redis.opsForValue().set("shop_" + userid, newToken);
            redis.expire("shop_" + userid, 36000, TimeUnit.SECONDS);
        }

        //写入访问日志
        //已在LogAop切面中实现
        //log.info(userid + "," + serverName + "," + serverPath);

        return true;
    }*/

    /*private boolean checkJwt(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader("user_token");
        String serverName = Func.getIP(request);
        String serverPath = request.getServletPath();

        //token为空，说明没有经过正常的登录操作
        if (Valid.isEmpty(token)) {
            log.info(serverName + "," + serverPath + ":" + ResultCode.USER_TOKEN_WEB_DELETION.getMessage());
            res.setVisitError(ResultCode.USER_TOKEN_WEB_DELETION);
            backException(response, res);
            return false;
        }

        //最好在JWT串加个前缀或后缀，获取时再去掉它，最后再解码（让窃取token值的人误以为这个前缀或后缀也是需要解码的一部分）
        token = token.replace("ly_", "");
        Jwt result = Jwts.parser().setSigningKey(param.getJwtPassword()).parse(token);
        JSONObject body = JSONObject.parseObject(result.getBody().toString());

        //token里的6项内容任意一项为空，都不正常
        String userid = body.getString("userid");
        String username = body.getString("username");
        String password = body.getString("password");
        String name = body.getString("name");
        String time = body.getString("time");
        String random = body.getString("random");
        if (Valid.isEmpty(userid) || Valid.isEmpty(username) || Valid.isEmpty(password) ||
                Valid.isEmpty(name) || Valid.isEmpty(time) || Valid.isEmpty(random)) {
            log.info(userid + "," + serverName + "," + serverPath + ":" + ResultCode.USER_TOKEN_CONTENT_EMPTY.getMessage());
            res.setVisitError(ResultCode.USER_TOKEN_CONTENT_EMPTY);
            backException(response, res);
            return false;
        }

        //用户ID的格式不正确
        if (userid.length() != 48) {
            log.info(userid + "," + serverName + "," + serverPath + ":用户ID的格式不正确");
            res.setVisitError("非法访问4");
            backException(response, res);
            return false;
        }

        //姓名的格式不正确
        if (name.length() > 10 || Valid.isWicked(name)) {
            log.info(userid + "," + serverName + "," + serverPath + ":姓名的格式不正确");
            res.setVisitError("非法访问5");
            backException(response, res);
            return false;
        }

        //随机数的格式不正确
        if (random.length() != 6) {
            log.info(userid + "," + serverName + "," + serverPath + ":随机数的格式不正确");
            res.setVisitError("非法访问6");
            backException(response, res);
            return false;
        }

        return true;
    }*/

    private void backException(HttpServletResponse response, Result res) {
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            response.getOutputStream().write(res.toString().getBytes("UTF-8"));
        } catch (Exception ex) {
            log.error("/Intercept/BackException:" + ex);
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

    }
}
